package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.mapper.EmpExprMapper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.*;
import com.itheima.service.EmpLogService;
import com.itheima.service.EmpService;
import com.itheima.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private EmpExprMapper empExprMapper;

    @Autowired
    private EmpLogService empLogService;

    /**
     * 分页条件查询
     *
     * @param empQueryParam
     * @return
     */
    @Override
    public PageResult<Emp> page(EmpQueryParam empQueryParam) {
        //分页查询
        //设置分页参数: p1:页码，p2:每页记录数, ThreadLocal + Mybatis QueryInterceptor
        PageHelper.startPage(empQueryParam.getPage(), empQueryParam.getPageSize());
        //紧跟着的第一个select方法会被分页， limit （page-1） * pageSize,pageSize
        Page<Emp> pageInfo = empMapper.list(empQueryParam);
        //日志中{}占位符，
        //分页时，实际返回的结果list类型是Page<E>，如果想取出分页信息，需要强制转换为Page<E>
        log.info("分页信息: {}", pageInfo);
        //getTotal获取总记录数
        //getResult获取分页结果
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getResult());
    }

    /**
     * 新增员工
     *
     * @param emp
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    //事务失效的场景：
    // rollbackFor默认是RuntimeException，如果是Exception，则事务失效。rollbackFor=Exception.class，只要出异常事务就回滚

    // 在方法进入前进行try-catch处理，先执行begin, 如果没报错则提交事务，报错就回滚事务
    // 如果使用@Transactional来管理事务，则不要在代码中使用try-catch，不要捕获异常，外部就无法捕获异常，外部认为内部没问题，没问题就提交事务
    public void add(Emp emp) throws Exception {
        //begin;
        try {
            //补充其它属性值
            emp.setCreateTime(LocalDateTime.now());
            emp.setUpdateTime(emp.getCreateTime());
            //往emp员工表添加数据
            empMapper.insert(emp);

            //int i = 10/0;
            /*if (emp.getId() != null) {
                throw new Exception("故意抛出异常");
            }*/
            //获取新增的员工id
            Integer newId = emp.getId();
            //判断是否有工作经历，有才添加
            List<EmpExpr> exprList = emp.getExprList();
            //if(null != exprList && exprList.size() > 0)
            //取反，isEmpty()为 空则返回true 取反 false，有工作经历
            if (!CollectionUtils.isEmpty(exprList)) {
                //设置新增的员工的id
                exprList.forEach(e -> e.setEmpId(newId));
                /*for (EmpExpr empExpr : exprList) {
                    //emp.getId()有值，新增的员工
                    empExpr.setEmpId(newId);
                }*/
                //添加员工的工作经历
                empExprMapper.insertBatch(exprList);
            }
            //commit;
            //} catch (Exception e) {
            //rollback;
            //throw new RuntimeException(e);
            //}
        }finally {
            empLogService.insertLog(new EmpLog(emp.getId(), LocalDateTime.now(), "新增员工"));
        }
    }

    /**
     * 批量删除员工信息
     *
     * @param ids
     */
    @Override
    @Transactional
    public void deleteByIds(List<Integer> ids) {
        //先删除员工信息
        // 批量删除
        empMapper.deleteByIds(ids);
        //再删除员工工作经历
        empExprMapper.deleteByEmpIds(ids);
    }

    /**
     * 通过id查询员工
     *
     * @param id
     * @return
     */
    public Emp getById2(Integer id) {
        // 多表关联拆成单表查询：数据量大，分表/库存储时使用。分布式项目
        //1、查询员工的基本信息
        Emp emp = empMapper.selectById(id);
        //2、员工的工作经历,通过员工的id查询
        List<EmpExpr> exprList = empExprMapper.selectByEmpId(id);
        // 设置员工对象的工作经历
        emp.setExprList(exprList);
        return emp;
    }
    @Override
    public Emp getById(Integer id) {
        //多表关联查询实现
        Emp emp = empMapper.selectInfoById(id);
        return emp;
    }

    /**
     * 修改员工
     *
     * @param emp
     */
    @Override
    @Transactional
    public void update(Emp emp) {
        //1. 先更新员工信息
        empMapper.updateById(emp);//所有数据都是从前端过来的，以前端为主，前端传什么，就更新什么,即使是空值或空串也要更新为 null或空串。不用动态更新语句
        //明确使用update语句，确定要更新的字段，不要使用动态更新语句
        //2. 删除旧的工作经历
        empExprMapper.deleteByEmpIds(Arrays.asList(emp.getId()));
        //3. 添加新的工作经历
        List<EmpExpr> exprList = emp.getExprList();
        if (!CollectionUtils.isEmpty(exprList)) {
            //设置员工的id
            exprList.forEach(e -> e.setEmpId(emp.getId()));
            empExprMapper.insertBatch(exprList);
        }
    }

    /**
     * 登录
     *
     * @param emp
     * @return
     */
    @Override
    public LoginInfo login(Emp emp) {
        //登录的本质：通过用户名与密码查询员工信息
        Emp empInDB = empMapper.selectByUsernameAndPassword(emp);
        if(null != empInDB){
            //生成token
            // 存储用户信息到令牌里，添加载荷【注意】：非敏感数据
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", empInDB.getId());
            claims.put("name", empInDB.getName());
            String token = JwtUtils.generateJwt(claims);
            //转成loginInfo对象
            return new LoginInfo(empInDB.getId(), empInDB.getUsername(), empInDB.getName(), token);
        }
        return null;
    }
}
